package nl.windgazer.arachne.services.facebook;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;

import org.apache.log4j.Logger;
import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.services.ApplicationStateManager;

public class FacebookOpenGraphDAOImp implements FacebookOpenGraphDAO {

	private static Logger logger = Logger.getLogger(FacebookOpenGraphDAOImp.class);

	public static final String FB_BASEURL = "https://graph.facebook.com/";
	public static final String FB_METHOD_FEED = "feed";

	private final FacebookAPISettings settings;
	private final ApplicationStateManager session;

	private FacebookUser user = null;

	public FacebookOpenGraphDAOImp(
			final FacebookAPISettings settings
			, final ApplicationStateManager session
	) {
		this.settings = settings;
		this.session = session;
	}

	public String publishFeed(String profileId, String accessToken,
			String message, String picture, String link, String name,
			String caption, String description, String source) throws FacebookOpenGraphException {

		final ArrayList<String> params = new ArrayList<String>();

		try {
//			if (accessToken!=null) {
//				params.add("access_token=");
//				params.add(URLEncoder.encode(accessToken, "UTF-8"));
//			}
			if (message!=null) {
				params.add("message");
				params.add(URLEncoder.encode(message, "UTF-8"));
			}
			if (picture!=null) {
				params.add("picture");
				params.add(URLEncoder.encode(picture, "UTF-8"));
			}
			if (link!=null) {
				params.add("link");
				params.add(URLEncoder.encode(link, "UTF-8"));
			}
			if (name!=null) {
				params.add("name");
				params.add(URLEncoder.encode(name, "UTF-8"));
			}
			if (caption!=null) {
				params.add("caption");
				params.add(URLEncoder.encode(caption, "UTF-8"));
			}
			if (description!=null) {
				params.add("description");
				params.add(URLEncoder.encode(description, "UTF-8"));
			}
			if (source!=null) {
				params.add("source");
				params.add(URLEncoder.encode(source, "UTF-8"));
			}
		} catch (UnsupportedEncodingException e) {
			return null;
		}

//		final StringBuilder usb = new StringBuilder();
//		usb.append(FB_BASEURL);
//		usb.append(profileId);
//		usb.append('/');
//		usb.append(FB_METHOD_FEED);
//		usb.append('?');
//		usb.append(getQueryString());
		
		return readOpenGraph(profileId, FB_METHOD_FEED, accessToken, params.toArray(new String[]{}));
		
//		try {
//
//			System.out.println(usb.toString());
//
//			URL urlObject = new URL(usb.toString());
//
//			HttpURLConnection urlConnection = (HttpURLConnection)urlObject.openConnection();
//
//			//Specifying that we intend to use this connection for input
//			urlConnection.setDoInput(true);
//
//			// Specifying that we intend to use this connection for output
//			urlConnection.setDoOutput(true);
//
//			// Specifying the content type of our post
//			urlConnection.setRequestProperty("Content-Type", "text/plain");
//
//			// Specifying the method of HTTP request which is POST
//			// throws ProtocolException
//			urlConnection.setRequestMethod("POST");
//
//			final DataOutputStream dataOutputStream = new DataOutputStream(urlConnection.getOutputStream());
//			 
//			// With the DataOutputStream object, the POST contents can simply be written using the folowing code.
//
//			System.out.println(sb.toString());
//			dataOutputStream.writeBytes(sb.toString());
//			dataOutputStream.flush();
//
//			// Prepare a reader to read the response from the URLConnection
//		    // throws IOException
//		 
//			final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
//			String responseLine;
//			 
//			// Good Practice: Use StringBuilder in this case
//			StringBuilder response = new StringBuilder();
//			 
//			// Read untill there is nothing left in the stream
//			// throws IOException
//			while ((responseLine = bufferedReader.readLine()) != null)
//			{
//			   response.append(responseLine);
//			}
//
//			// And finally don't forget to close the output stream to free up any resources used.
//			dataOutputStream.close();
//			bufferedReader.close();
//
//			System.out.println(response.toString());
//
//			return response.toString();
//
//		} catch (MalformedURLException e) {
//			return null;
//		} catch (IOException e) {
//			e.printStackTrace();
//			return null;
//		}

	}

	private String getQueryString(final String ... params) {

		final StringBuilder sb = new StringBuilder();
		boolean name = true;

		for (final String s:params) {
			if (sb.length()>0) {
				sb.append(name?'&':'=');
			}
			try {
				sb.append(URLEncoder.encode(s, "UTF-8"));
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			name = !name;
		}

		return sb.toString();

	}

	public String readOpenGraph(final String id, final String link, final String token, final String ... params) throws FacebookOpenGraphException {

		final StringBuilder sb = new StringBuilder();

		final StringBuffer uri = new StringBuffer();
		uri.append("https://graph.facebook.com/");
		uri.append(id);

		if (link!=null) {
			uri.append('/');
			uri.append(link);
		}

		if (token!=null) {
			uri.append('?');
			uri.append(getQueryString("access_token", token));
		}
		
		if (params!=null) {
			uri.append((token!=null)?'&':'?');
			uri.append(getQueryString(params));
		}

		try {
			logger.error(uri);
			URL graphURL = new URL(uri.toString());
			BufferedReader in = new BufferedReader( new InputStreamReader( graphURL.openStream() ) );
			String inputLine;
			while ((inputLine = in.readLine()) != null)
				sb.append(inputLine);
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		System.out.println(uri.toString());
		System.out.println(sb.toString());

		if (sb.length() < 1 || sb.charAt(0)!='{') {
			throw new FacebookOpenGraphException(sb.toString());
		}

		return sb.toString();

	}

	public String readOpenGraph(final String id, final String link) throws FacebookOpenGraphException {
		return readOpenGraph(id, link, settings.getSettings().get("access_token"));
	}

	public FacebookUser getUser() throws FacebookOpenGraphException {
		if (!settings.isVerified()) {
			session.set(FacebookUser.class, null);
			return null;
		}
		if (user==null) {
			user = session.getIfExists(FacebookUser.class);
			if (user == null || !user.getUID().equals(settings.getSettings().get("uid"))) { //If no user is stored in the session, or the uid doesn't match
				try {
					user = new FacebookUserImp(new JSONObject(readOpenGraph("me", null)));
				} catch (FacebookOpenGraphException e) {
					session.set(FacebookUser.class, null); //Invalidating possible previous information
					throw new FacebookOpenGraphException("Failed to retreive user due to a communication error!");
				}
				session.set(FacebookUser.class, user);
			}
		}
		return user;
	}
}
